#include "internal.h"

static void enqueue_top_rt_rq(struct rt_rq *rt_rq);
static void __enqueue_rt_entity(struct sched_rt_entity *rt_se, unsigned int flags);

static void dequeue_top_rt_rq(struct rt_rq *rt_rq, unsigned int count)
{
    struct rq *rq = rq_of_rt_rq(rt_rq);

    BUG_ON(&rq->rt != rt_rq);

    if (!rt_rq->rt_queued)
        return;

    BUG_ON(!rq->nr_running);

    sub_nr_running(rq, count);
    rt_rq->rt_queued = 0;
}

static void __dequeue_rt_entity(struct sched_rt_entity *rt_se, unsigned int flags)
{
    struct rt_rq *rt_rq = rt_rq_of_se(rt_se);
    struct rt_prio_array *array = &rt_rq->active;

    if (move_entity(flags))
    {
        WARN_ON_ONCE(!rt_se->on_list);
        __delist_rt_entity(rt_se, array);
    }
    rt_se->on_rq = 0;

    dec_rt_tasks(rt_se, rt_rq);
}

/*
 * Because the prio of an upper entry depends on the lower
 * entries, we must remove entries top - down.
 */
static void dequeue_rt_stack(struct sched_rt_entity *rt_se, unsigned int flags)
{
    struct sched_rt_entity *back = NULL;
    unsigned int rt_nr_running;

    for_each_sched_rt_entity(rt_se)
    {
        rt_se->back = back;
        back = rt_se;
    }

    rt_nr_running = rt_rq_of_se(back)->rt_nr_running;

    for (rt_se = back; rt_se; rt_se = rt_se->back)
    {
        if (on_rt_rq(rt_se))
            __dequeue_rt_entity(rt_se, flags);
    }

    dequeue_top_rt_rq(rt_rq_of_se(back), rt_nr_running);
}

static void dequeue_rt_entity(struct sched_rt_entity *rt_se, unsigned int flags)
{
    struct rq *rq = rq_of_rt_se(rt_se);

    update_stats_dequeue_rt(rt_rq_of_se(rt_se), rt_se, flags);

    dequeue_rt_stack(rt_se, flags);

    for_each_sched_rt_entity(rt_se)
    {
        struct rt_rq *rt_rq = group_rt_rq(rt_se);

        if (rt_rq && rt_rq->rt_nr_running)
            __enqueue_rt_entity(rt_se, flags);
    }
    enqueue_top_rt_rq(&rq->rt);
}

static bool dequeue_task_rt(struct rq *rq, struct task_struct *p, int flags)
{
    struct sched_rt_entity *rt_se = &p->rt;

    update_curr_rt(rq);
    dequeue_rt_entity(rt_se, flags);

    dequeue_pushable_task(rq, p);

    return true;
}
